#!/usr/bin/env nu
# Info: Script to run Provisioning Version Management
# Author: JesusPerezLorenzo
# Release: 1.0.0
# Date: 29-09-2025

use std log

use lib_provisioning *
use env.nu *

# - > Help on Version Management
export def "main help" [
  --src: string = ""
  --notitles       # not titles
  --out: string    # Print Output format: json, yaml, text (default)
]: nothing -> nothing {
  if $notitles == null or not $notitles { show_titles }
  ^$"($env.PROVISIONING_NAME)" -mod version --help
  if ($out | is-not-empty) { $env.PROVISIONING_NO_TERMINAL = false }
  print (provisioning_options $src)
  if not $env.PROVISIONING_DEBUG { end_run "" }
}

# > Version Management
# Manage component versions, check updates, and apply configuration changes
#
# Commands:
#   check    - Check all component versions (taskservs, tools, providers)
#   show     - Display version status with formatting options
#   updates  - Check for available updates from upstream sources
#   apply    - Apply config updates after manual installation
#   taskserv - Show specific taskserv version information
#   tools    - Show tool versions (nushell, kcl, sops, etc.)
#
# Workflow:
#   1. Run 'version updates' to check for new versions
#   2. Manually install updated components (follow guidance)
#   3. Run 'version apply' to update configuration files
#   4. Run 'version check' to verify installations
#
# Examples:
#   provisioning version check                    # Check all versions
#   provisioning version show --format table      # Display version table
#   provisioning version updates                  # Check for updates
#   provisioning version apply --dry-run          # Preview config updates
#   provisioning version taskserv kubernetes      # Show k8s version info
#   provisioning version tools                    # Show tool versions
def main [
  ...args: string  # Other options, use help to get info
  -v               # Show version
  -i               # Show Info
  --version (-V)   # Show version with title
  --info (-I)      # Show Info with title
  --about (-a)     # Show About
  --path: string = ""  # Base path to search for components
  --types: list = []   # Filter by component types
  --format: string = "table"  # Output format: table, json, yaml
  --group-by: string = "type"  # Group results by: type, status, name
  --fetch-latest = false  # Fetch latest versions from upstream
  --dry-run        # Preview changes without applying
  --force          # Force update even if version is fixed
  --check (-c)     # Only check mode, no actual changes
  --yes (-y)       # Confirm task
  --debug (-x)     # Use Debug mode
  --xm             # Debug with PROVISIONING_METADATA
  --xld            # Log level with DEBUG PROVISIONING_LOG_LEVEL=debug
  --metadata       # Error with metadata (-xm)
  --notitles       # Do not show banner titles
  --helpinfo (-h)  # For more details use options "help" (no dashes)
  --out: string    # Print Output format: json, yaml, text (default)
]: nothing -> nothing {
  if ($out | is-not-empty) {
    $env.PROVISIONING_OUT = $out
    $env.PROVISIONING_NO_TERMINAL = true
  }
  provisioning_init $helpinfo "version" $args
  if $version or $v { ^$env.PROVISIONING_NAME -v ; exit }
  if $info or $i { ^$env.PROVISIONING_NAME -i ; exit }
  if $about {
    _print (get_about_info)
    exit
  }
  if $debug { $env.PROVISIONING_DEBUG = true }
  if $metadata { $env.PROVISIONING_METADATA = true }

  let task = if ($args | length) > 0 { ($args | get 0) } else { "" }
  let ops = if ($args | length) > 1 { ($args | skip 1 | str join " ") } else { "" }
  let component_name = if ($ops | is-not-empty) and not ($ops | str starts-with "-") {
    ($ops | split row " " | get 0)
  } else {
    ""
  }

  $env.PROVISIONING_MODULE = "version"

  match $task {
    "h" => {
      exec $"($env.PROVISIONING_NAME)" -mod version help --notitles
    },
    "check" => {
      print "🔍 Checking component versions..."
      version_check --path $path --types $types --out $out
    },
    "show" => {
      print "📊 Displaying version status..."
      version_show --path $path --types $types --format $format --group-by $group_by --out $out
    },
    "updates" => {
      print "🔎 Checking for available updates..."
      version_updates --path $path --types $types --out $out
    },
    "apply" => {
      if $dry_run {
        print "🔍 Preview mode: showing changes without applying..."
        version_apply --path $path --types $types --dry-run --force $force --out $out
      } else if $force {
        print "⚠️  Force mode: updating even fixed versions..."
        version_apply --path $path --types $types --force --out $out
      } else {
        print "📝 Applying configuration updates..."
        version_apply --path $path --types $types --out $out
      }
    },
    "taskserv" => {
      if ($component_name | is-empty) {
        print "❌ Please specify a taskserv name"
        print "Usage: provisioning version taskserv <name>"
        exit 1
      }
      print $"📦 Showing taskserv version: ($component_name)"
      version_taskserv $component_name --out $out
    },
    "tools" => {
      print "🔧 Showing tool versions..."
      version_tools --out $out
    },
    _ => {
      print $"❌ Unknown task: ($task)"
      print "Use 'provisioning version help' for available commands"
      exit 1
    }
  }
}

# Check all component versions
def version_check [
  --path: string
  --types: list
  --out: string
]: nothing -> nothing {
  use lib_provisioning/utils/version_manager.nu check-versions

  let results = if ($types | is-empty) {
    check-versions --path=$path
  } else {
    check-versions --path=$path --types=$types
  }

  if ($out | is-not-empty) {
    if $out == "json" {
      print ($results | to json)
    } else if $out == "yaml" {
      print ($results | to yaml)
    } else {
      print ($results | table)
    }
  } else {
    print ($results | table)
  }
}

# Display version status with formatting
def version_show [
  --path: string
  --types: list
  --format: string
  --group-by: string
  --out: string
]: nothing -> nothing {
  use lib_provisioning/utils/version_manager.nu show-versions

  let output_format = if ($out | is-not-empty) { $out } else { $format }

  if ($types | is-empty) {
    show-versions --path=$path --format=$output_format --group-by=$group_by
  } else {
    show-versions --path=$path --types=$types --format=$output_format --group-by=$group_by
  }
}

# Check for available updates
def version_updates [
  --path: string
  --types: list
  --out: string
]: nothing -> nothing {
  use lib_provisioning/utils/version_manager.nu check-available-updates

  if ($types | is-empty) {
    check-available-updates --path=$path
  } else {
    check-available-updates --path=$path --types=$types
  }
}

# Apply configuration updates after installation
def version_apply [
  --path: string
  --types: list
  --dry-run = false
  --force = false
  --out: string
]: nothing -> nothing {
  use lib_provisioning/utils/version_manager.nu apply-config-updates

  if $dry_run and $force {
    if ($types | is-empty) {
      apply-config-updates --path=$path --dry-run --force
    } else {
      apply-config-updates --path=$path --types=$types --dry-run --force
    }
  } else if $dry_run {
    if ($types | is-empty) {
      apply-config-updates --path=$path --dry-run
    } else {
      apply-config-updates --path=$path --types=$types --dry-run
    }
  } else if $force {
    if ($types | is-empty) {
      apply-config-updates --path=$path --force
    } else {
      apply-config-updates --path=$path --types=$types --force
    }
  } else {
    if ($types | is-empty) {
      apply-config-updates --path=$path
    } else {
      apply-config-updates --path=$path --types=$types
    }
  }
}

# Show specific taskserv version information
def version_taskserv [
  name: string
  --out: string
]: nothing -> nothing {
  use lib_provisioning/utils/version_manager.nu check-versions

  let results = (check-versions --types=["taskserv"] --fetch-latest=true)
  let taskserv = ($results | where id == $name | get -o 0)

  if ($taskserv | is-empty) {
    print $"❌ Taskserv '($name)' not found"
    print "Available taskservs:"
    $results | select id configured installed status | table
    exit 1
  }

  if ($out | is-not-empty) {
    if $out == "json" {
      print ($taskserv | to json)
    } else if $out == "yaml" {
      print ($taskserv | to yaml)
    } else {
      print ($taskserv | table)
    }
  } else {
    print $"📦 Taskserv: ($taskserv.id)"
    print $"  Type: ($taskserv.type)"
    print $"  Configured: ($taskserv.configured)"
    print $"  Installed: ($taskserv.installed)"
    print $"  Latest: ($taskserv.latest? | default 'N/A')"
    print $"  Status: ($taskserv.status)"
    print $"  Fixed: ($taskserv.fixed? | default false)"
  }
}

# Show tool versions
def version_tools [
  --out: string
]: nothing -> nothing {
  use lib_provisioning/utils/version_manager.nu check-versions

  let results = (check-versions --types=["tool"] --fetch-latest=false)

  if ($out | is-not-empty) {
    if $out == "json" {
      print ($results | to json)
    } else if $out == "yaml" {
      print ($results | to yaml)
    } else {
      print ($results | table)
    }
  } else {
    print "🔧 Tool Versions:"
    $results | select id configured installed status | table
  }
}
